import {Task} from "./Task";
import fsExtra from "fs-extra";
import path from "path";

const puppeteer = require('puppeteer');

export class PuppeteerTask extends Task {
  constructor(config) {
    super(config);
    
    this.browser = null;
    this.page = null;
    this.count = 0;
    fsExtra.ensureDirSync(path.join(__dirname, `../../static/result/${this.taskId}/screenshot`));
  }
  
  getPage() {
    return this.page;
  }
  
  async run() {
    this.browser = await puppeteer.launch(
      {
        // executablePath: '/root/app/chrome-linux/chrome',
        executablePath: process.env.ChromeExecutablePath,
        headless: true,
        devtools: true,
        args: ['--no-sandbox', '--disable-setuid-sandbox',
          process.env.NODE_ENV == 'test' ? '--proxy-server=http://172.22.225.70:23128' : ''
        ]
      }
    );
    this.page = await this.browser.newPage();
    // await this.page.setDefaultNavigationTimeout(5000);
    await this.page.setViewport({
      width: 414,
      height: 736
    });
    await this.page.setJavaScriptEnabled(true);
    // console.log('goto',this.entranceUrl);
    await this.page.goto(this.entranceUrl);
    // console.log('goto完成');
    
    await this.login();
    let clickDetailList = await this.sniffer(0, this.entranceUrl);
    console.log(clickDetailList);
    fsExtra.writeJsonSync(path.join(__dirname, `../../static/result/${this.taskId}/result.json`), clickDetailList)
    
    // let clickableElements = await this.getAllClickableElements();
    // await clickableElements[0].click();
    // await this.waitForJump();
    // await this.getPage().goto(this.entranceUrl);
    await this.browser.close();
  }
  
  async sniffer(depth, lastUrl) {
    await this.screenshot();
    let clickDetailList = [];
    let clickableElements = await this.getAllClickableElements();
    let index = 0;
    while (index < clickableElements.length) {
      let clickDetail = {
        depth,
        url: this.getPage().url(),
        element: '',
        result: '',
        screenshotPath: ''
      };
      let element = clickableElements[index];
      clickDetail.element = `depth:${depth} 点击第${index + 1}个(共${clickableElements.length}) ${element._remoteObject.description} ${element._remoteObject.objectId}`;
      console.log(clickDetail.element);
      try {
        await element.click();
        await this.waitForJump();
        
        if (this.getPage().url() != lastUrl) {
          let screenshotPath = await this.screenshot();
          clickDetail.result = this.getPage().url();
          clickDetail.screenshotPath = screenshotPath;
          console.log(this.getPage().url());
          if (depth < this.maxDepth - 1) {
            let nextPageClickDetailList = await this.sniffer(depth + 1, this.getPage().url());
            clickDetail.result = nextPageClickDetailList;
          }
          await this.getPage().goto(lastUrl);
          await this.waitForJump();
          console.log('goback', this.getPage().url());
          
          clickableElements = await this.getAllClickableElements();
        } else {
          clickDetail.result = '地址未变';
          console.log('地址未变');
        }
      } catch (e) {
        clickDetail.result = 'click error:' + e;
        console.log('click error', e);
      }
      
      index++;
      clickDetailList.push(clickDetail);
    }
    
    return clickDetailList;
  }
  
  async getEventListeners(element) {
    const listeners = await element._client.send('DOMDebugger.getEventListeners', {
      objectId: element._remoteObject.objectId,
    })
    return listeners;
  }
  
  async getAllClickableElements() {
    let clickableElements = [];
    let allElements = await this.getPage().$$('*');
    // console.log(allElements.length);
    for (let element of allElements) {
      try {
        let listeners = (await this.getEventListeners(element)).listeners;
        // console.log(listeners);
        for (let listener of listeners) {
          if (listener.type == 'click') {
            clickableElements.push(element);
          }
        }
        
      } catch (e) {
        console.log(e);
      }
    }
    return clickableElements;
  }
  
  async waitForJump() {
    try {
      await this.getPage().waitForNavigation({
          timeout: 5000,
          waitUntil: 'networkidle0'
        }
      );
    } catch (e) {
      // console.log('超时',e);
    }
  }
  
  async login() {
    let page = this.getPage();
    // await screenshot(page);
    // await page.click('#changeSms')
    // await screenshot(page);
    await page.type('#phone', '14715001130', {delay: 20});
    // await screenshot(page);
    await page.click('#getMsg')
    // await screenshot(page);
    await page.type('#code', '694071', {delay: 20});
    // await screenshot(page);
    await page.click('#loginBtn')
    // await page.waitForNavigation({waitUntil:'networkidle0'});
    await this.waitForJump();
  }
  
  async screenshot() {
    this.count++;
    await this.getPage().screenshot({
      path: path.join(__dirname, `../../static/result/${this.taskId}/screenshot/screenshot-${this.count}.jpeg`),
      fullpage: true,
      type: 'jpeg',
      quality: 50
    });
    return `/website/auxiliaryTool/static/result/${this.taskId}/screenshot/screenshot-${this.count}.jpeg`;
    
  }
}